//  通过构造函数创建对象时，如果把方法放到实力对象身上，会导致创建多个对象时，方法也跟着创建多个，造成内存浪费
function Person(name,age){
    this.name = name
    this.age = age
    this.sayHi = function(){
        console.log('你好')
    }
}
const zs = new Person('张三',18)
console.log(zs) //  Person { name: '张三', age: 18, sayHi: [Function (anonymous)] }
zs.sayHi() // 你好


const ls = new Person('李四',19)
console.log(ls) // Person { name: '李四', age: 19, sayHi: [Function (anonymous)] }
ls.sayHi() // 你好

console.log(zs.sayHi === ls.sayHi) // false 证明内存地址不一样

// 解决：使用原型对象
/**  特点
 * 所有通过构造函数创建出来的实例对象，都可以访问原型对象中的成员
 * 实例对象创建时，不会重复创建原型对象，每个构造函数的原型对象时唯一的，因为他是跟随构造函数走的
 * 对象会优先找自己身上的属性和方法，找不到才去原型上查找属性和方法
 */

function Person2(name,age){
    this.name = name
    this.age = age
}
//  想原型对象里加方法
Person2.prototype.sayHi = function(){
    console.log('你好,原型')
}
const zs2 = new Person2('张三',18)
console.log(zs2) //  Person2 { name: '张三', age: 18, sayHi: [Function (anonymous)] }
zs2.sayHi() // 你好,原型


const ls2 = new Person2('李四',19)
console.log(ls2) // Person2 { name: '李四', age: 19, sayHi: [Function (anonymous)] }
ls2.sayHi() // 你好,原型

console.log(zs2.sayHi === ls2.sayHi) // true


function Student(name,age,gender){
   this.name = name 
   this.age = age
   this.gender = gender
}
// 公共的属性和方法放在原型上    原型方法中的 this  指向 ： 调用者
/**
 * 1.构造函数不能时箭头函数，因为箭头函数的  this  指向  和当前环境有关
 * 2.原型的函数要根据情况判断，如果用了箭头函数就意味着  this  不再指向实例对象了
 */
Student.prototype.class = '计网6班'
Student.prototype.study = function (){
   return this.name + '会学习'
}
const s1 = new Student('邹希晨',22,'男')
console.log(s1)
console.log(s1.study()) // 邹希晨会学习

const s2 = new Student('青雀',20,'女')
console.log(s2)
console.log(s2.study()) // 青雀会学习


//  使用原型 给数组创建方法
Array.prototype.max = function(){
    // 求最大值
    return Math.max(...this)
}

Array.prototype.sum = function(){
    // 求和
    return this.reduce((prev,item)=> prev +item,0)
}

const arr1 = [1,2,3]
const arr2 = [10,20,30]
console.log(arr1.max()) // 3
console.log(arr2.max()) //30

console.log(arr1.sum()) // 6

console.log(arr2.sum()) // 60


//  原型 方法简写

function Student2(name,age){
    this.name = name
    this.age = age
}
// 每一个构造函数都  存在 constructor
// Student2.prototype.sayHi = function(){
// }
// Student2.prototype.eat = function(){
// }

// 简写  但是 会失去 constructor   解决 ： 就是指定   constructor  
Student2.prototype = {
    constructor:Student2,
    sayHi(){},
    eat(){},
    sleep(){},
    drip(){}
}
// 实例对象
const stu2 = new Student2('符玄',20)
const stu3 = new Student2('青雀',20)
console.log(stu2)
console.log(stu2.__proto__ === Student2.prototype) // true
console.log(stu3.__proto__ === Student2.prototype) // true
console.log(stu2.__proto__ === stu3.__proto__ ) // true

/**
 * 构造函数通过实例对象里面的 __proto__  指向原型对象
 * 原型对象存在于构造函数里面
 *  __proto__  不是标准属性，在浏览器中显示为  [[Prototype]]
 */



// 原型链 ： 查找规则
// 在实例对象中找  属性 和 方法， 如果找不到，会找 __proto__
// 原型对象中也找不到，在找原型对象的 __proto__
// 逐级向上找，查找的 Object  的原型对象为止，如果都找不到那就真没有

function Student3(name,age){
    this.name = name
    this.age = age
    // this.sayHi = function(){
    //     console.log('实例上的属性方法')
    // }
}
Student3.prototype.sayHi = function(){
    console.log(this.name) // 邹希晨
}
// Object.prototype.sayHi = function(){
//     console.log('object 的方法')
// }
const zxc = new Student3('邹希晨',18)
zxc.sayHi() 

console.log(zxc.__proto__ === Student3.prototype)  //true
console.log(Student3.prototype.__proto__ === Object.prototype)//true
console.log(Object.prototype.__proto__)//null


//   zxc.sayHi()  查找的级别  ：  实例上的属性和方法  -->  原型对象上的属性和方法   --> Object 上的属性和方法